package pt.ua.miect.sd.simuladorpesca.threads;

import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import org.apache.log4j.Logger;
import pt.ua.miect.sd.simuladorpesca.SimulationConfig;
import pt.ua.miect.sd.simuladorpesca.entities.*;

public class FishSchoolWorker implements Runnable, ISimWorker {

    private CyclicBarrier tickBarrier;
    private FishSchool school;
    private Thread t;
    private SimulatorSeasons currentSeason;

    public FishSchoolWorker(String fishId, CyclicBarrier tbarrier) {
        this(tbarrier, new FishSchool(fishId, MapPosition.genRandomPosition()));
    }

    public FishSchoolWorker(CyclicBarrier tbarrier, FishSchool school) {
        this.tickBarrier = tbarrier;
        this.school = school;
        Map.getInstance().addEntity(school.getId(), school);
        t = new Thread(this);
        //Simulator.registerWorker(this);
    }

    @Override
    public void start() {
        t.start();
    }

    @Override
    public void run() {
        //set inicial condition
        int moveCountDown = SimulationConfig.FISH_MOVE_RATIO; //fish moving speed
        int seasonCountDown = SimulationConfig.SPROWNING_SEASON_LENGHT;
        currentSeason = SimulatorSeasons.Spowning_Season;
        MapPosition spowningArea = null; //area where the fish will reproduce
        boolean setup = false;
        while (!setup) {
            spowningArea = MapPosition.getRandomShoalArea();
            setup = Map.getInstance().allowMove(school, spowningArea);
            school.setStatus(FishSchool.FishSchoolState.SPAWNING_AREA);
        }

        boolean done = false;
        while (!done) {
            try {
                tickBarrier.await();
                FishSchool.FishSchoolState status = school.getStatus();

                switch (status) {
                    case MOVING_TO_SPAWNING_AREA:
                        if (school.getMapPosition().equals(spowningArea)) {
                            Logger.getRootLogger().info(school.getId() + " has reached spawning area at " + school.getMapPosition().toString());
                            school.setStatus(FishSchool.FishSchoolState.SPAWNING_AREA);
                        } else {
                            Logger.getRootLogger().info(school.getId() + " is moving back to the Spawning Area " + spowningArea.toString());
                            List<MapPosition> routes = MapPosition.getRoutesTo(school.getMapPosition(), spowningArea, true);
                            for (MapPosition route : routes) {
                                boolean moved = Map.getInstance().allowMove(school, route);
                                if (moved) {
                                    Logger.getRootLogger().info(school.getId() + " has moved to position " + school.getMapPosition());
                                    break;
                                }
                            }
                        }
                        break;
                    case SPAWNING_AREA:
                        school.growFish();
                        break;
                    case FEEDING_AREA:
                        moveCountDown--;
                        if (moveCountDown == 0) {
                            moveCountDown = SimulationConfig.FISH_MOVE_RATIO;
                            List<MapPosition> moves = MapPosition.getValidMovements(school.getMapPosition());
                            for (MapPosition pos : moves) {
                                if (pos != null && Map.getInstance().allowMove(school, pos))
                                {
                                    //moved
                                     Logger.getRootLogger().info(school.getId() + " has moved to position " + school.getMapPosition());
                                     break;
                                }
                            }
                          
                        }
                        break;
                    case TRAPPED_IN_NET:
                        Logger.getRootLogger().info(school.getId() + " is trapped in a Net... They have now "+school.getFishPopulation()+" fish!");
                        break;
                }

                seasonCountDown--;
                if (seasonCountDown <= 0) {
                    switch (currentSeason) {
                        case Spowning_Season:
                            //moving to next season
                            currentSeason = SimulatorSeasons.Fishing_Season;
                            seasonCountDown = SimulationConfig.FISHING_SEASON_LENGHT;
                            break;
                        case Fishing_Season:
                            currentSeason = SimulatorSeasons.Spowning_Season;
                            seasonCountDown = SimulationConfig.SPROWNING_SEASON_LENGHT;
                            school.setStatus(FishSchool.FishSchoolState.MOVING_TO_SPAWNING_AREA);
                        //spowningArea = MapPosition.getNearestShoalArea(school.getMapPosition());
                    }
                }

            } catch (InterruptedException ex) {
                Logger.getLogger(CompanyOperationsWorker.class).error(ex);
                done = false;
            } catch (BrokenBarrierException ex) {
                Logger.getLogger(CompanyOperationsWorker.class).error(ex);
                done = false;
            }

        }

    }
}
